
#region Using Statements

    using System;
    using System.Collections.Generic;
    using System.Linq;

    using System.Diagnostics;
    using System.Text;

    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Audio;
    using Microsoft.Xna.Framework.Content;
    using Microsoft.Xna.Framework.GamerServices;
    using Microsoft.Xna.Framework.Graphics;
    using Microsoft.Xna.Framework.Input;
    using Microsoft.Xna.Framework.Media;
    using Microsoft.Xna.Framework.Net;
    using Microsoft.Xna.Framework.Storage;

#endregion

namespace HumanElement.Xna.Construct
{
    /// <summary>
    /// This is the Game Host class for the Construct Design Time game
    /// development tools.
    /// </summary>
    /// <typeparam name="TGame">The type of the game.</typeparam>
    public class GameHost<TGame> : IServiceProvider, IGameHost<TGame>, IDisposable
        where TGame : Game, new()
    {
        private Action _gameThread;

        /// <summary>
        /// Initializes a new instance of the <see cref="GameHost"/> class.
        /// </summary>
        protected GameHost() : base()
        {
            Services = new Dictionary<Type, IEntityManager>();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="GameHost&lt;TGame&gt;"/> class.
        /// </summary>
        /// <param name="game">The game.</param>
        /// <param name="gameManifest">The game manifest.</param>
        public GameHost(TGame game, GameManifest gameManifest) : this()
        {
            this.Game = game;
            this.GameManifest = gameManifest;
            
            _gameThread = new Action(Game.Run);
        }
        
        /// <summary>
        /// Gets the content manager.
        /// </summary>
        /// <value>The content manager.</value>
        public ContentManager ContentManager
        {
            get
            {
                return this.Game.Content;
            }
        }
        
        /// <summary>
        /// Gets or sets the game.
        /// </summary>
        /// <value>The game.</value>
        public TGame Game
        {
            get;
            private set;
        }
        
        /// <summary>
        /// Gets or sets the game manifest.
        /// </summary>
        /// <value>The game manifest.</value>
        public GameManifest GameManifest
        {
            get;
            set;
        }
        
        /// <summary>
        /// Gets a value indicating whether [game paused].
        /// </summary>
        /// <value><c>true</c> if [game paused]; otherwise, <c>false</c>.</value>
        public bool GamePaused
        {
            get;
            private set;
        }
                
        /// <summary>
        /// Gets or sets the last game time.
        /// </summary>
        /// <value>The last game time.</value>
        public GameTime LastGameTime
        {
            get;
            private set;
        }
        
        /// <summary>
        /// Gets a value indicating whether this <see cref="IGameHost"/> is paused.
        /// </summary>
        /// <value><c>true</c> if paused; otherwise, <c>false</c>.</value>
        public bool Paused
        {
            get;
            set;
        }
        
        /// <summary>
        /// Gets the players.
        /// </summary>
        /// <value>The players.</value>
        public int Players
        {
            get;
            private set;
        }
        
        /// <summary>
        /// Gets or sets the sprite batch.
        /// </summary>
        /// <value>The sprite batch.</value>
        public SpriteBatch SpriteBatch
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the systems.
        /// </summary>
        /// <value>The systems.</value>
        public Dictionary<Type, IEntityManager> Services
        {
            get;
            set;
        }
        
        /// <summary>
        /// Gets the game instance.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <returns></returns>
        public Game GetGameInstance(Type type)
        {
            return (Game.GetType() == type) ? this.Game : null;  
        }
        
        /// <summary>
        /// Gets the service object of the specified type.
        /// </summary>
        /// <param name="serviceType">An object that specifies the type of service object to get.</param>
        /// <returns>
        /// A service object of type <paramref name="serviceType"/>.
        /// -or-
        /// null if there is no service object of type <paramref name="serviceType"/>.
        /// </returns>
        public object GetService(Type serviceType)
        {
            var ret = Services[serviceType];

            return ret;
        }

        /// <summary>
        /// Tries the get service.
        /// </summary>
        /// <typeparam name="TService">The type of the service.</typeparam>
        /// <returns></returns>
        public bool TryGetService<TService>(out TService service) where TService : IEntityManager
        {
            var ret = false;

            if(Services.ContainsKey(typeof(TService)))
            {
                service = (TService) Services[typeof (TService)];
                ret = true;
            }
            else
            {
                service = default(TService);
            }

            return ret;
        }

        /// <summary>
        /// Launches this instance.
        /// </summary>
        public void Launch()
        {
            _gameThread = new Action(Game.Run);

            _gameThread();
        }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
        }

        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
        public void Dispose(bool disposing)
        {
            if(disposing)
            {
                Game.Dispose();
                ContentManager.Dispose();               
            }
        }

        /// <summary>
        /// Gets the game host.
        /// </summary>
        /// <value>The game host.</value>
        IGameHost IEntityManager.GameHost
        { 
            get
            {
                return this;
            }
        }

        /// <summary>
        /// Gets or sets the update frequency.
        /// </summary>
        /// <value>The update frequency.</value>
        public float UpdateFrequency
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether this <see cref="IEntity"/> is enabled.
        /// </summary>
        /// <value><c>true</c> if enabled; otherwise, <c>false</c>.</value>
        public bool Enabled
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        /// <summary>
        /// Gets or sets the name.
        /// </summary>
        /// <value>The name.</value>
        public string Name
        {
            get;
            set;
        }

        /// <summary>
        /// Updates the specified game time.
        /// </summary>
        /// <param name="gameTime">The game time.</param>
        public void Update(GameTime gameTime)
        {
            
        }

        /// <summary>
        /// Initializes the specified game host.
        /// </summary>
        /// <param name="game">The game.</param>
        public void Initialize(IGame game)
        {
            throw new NotImplementedException();
        }

    }
}
